package com.stellar.core.util;


import cn.hutool.crypto.CryptoException;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;

/**
 * 安全密码加解密工具类 (AES-GCM 模式)
 * 注意：生产环境请务必妥善保管密钥和盐值
 */
public class CryptoUtils {

    // 算法配置
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    private static final int TAG_LENGTH_BIT = 128;
    private static final int IV_LENGTH_BYTE = 12;
    private static final int SALT_LENGTH_BYTE = 16;
    private static final int ITERATION_COUNT = 65536;
    private static final int KEY_LENGTH_BIT = 256;

    // 从安全配置源获取以下参数
    private static final String SECRET_KEY = "LanYunSuperSecretKey";

    /**
     * 加密方法
     *
     * @param plaintext 明文
     * @return Base64编码的加密字符串（格式：盐值 + IV + 密文）
     */
    public static String encrypt(String plaintext) throws CryptoException {
        try {
            // 生成随机盐值（实际建议每个密码单独存储盐值）
            byte[] salt =  generateSalt();

            // 派生密钥
            SecretKey secretKey = deriveKey(SECRET_KEY.toCharArray(), salt);

            // 生成IV
            byte[] iv = new byte[IV_LENGTH_BYTE];
            SecureRandom.getInstanceStrong().nextBytes(iv);

            // 初始化加密器
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LENGTH_BIT, iv));

            // 执行加密
            byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

            // 组合盐值 + IV + 密文
            byte[] combined = new byte[salt.length + iv.length + ciphertext.length];
            System.arraycopy(salt, 0, combined, 0, salt.length);
            System.arraycopy(iv, 0, combined, salt.length, iv.length);
            System.arraycopy(ciphertext, 0, combined, salt.length + iv.length, ciphertext.length);

            return Base64.getUrlEncoder().encodeToString(combined);
        } catch (Exception e) {
            throw new CryptoException("加密失败", e);
        }
    }

    /**
     * 解密方法
     *
     * @param ciphertext Base64编码的加密字符串
     * @return 解密后的明文
     */
    public static String decrypt(String ciphertext) throws CryptoException {
        try {
            // 解码Base64
            byte[] combined = Base64.getUrlDecoder().decode(ciphertext);

            // 提取各部分
            int pos = 0;
            byte[] salt = new byte[SALT_LENGTH_BYTE];
            System.arraycopy(combined, pos, salt, 0, salt.length);
            pos += salt.length;

            byte[] iv = new byte[IV_LENGTH_BYTE];
            System.arraycopy(combined, pos, iv, 0, iv.length);
            pos += iv.length;

            byte[] ct = new byte[combined.length - pos];
            System.arraycopy(combined, pos, ct, 0, ct.length);

            // 派生密钥
            SecretKey secretKey = deriveKey(SECRET_KEY.toCharArray(), salt);

            // 初始化解密器
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LENGTH_BIT, iv));

            // 执行解密
            byte[] plaintext = cipher.doFinal(ct);
            return new String(plaintext, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new CryptoException("解密失败", e);
        }
    }

    /**
     * 使用PBKDF2派生密钥
     */
    private static SecretKey deriveKey(char[] password, byte[] salt)
            throws NoSuchAlgorithmException, InvalidKeySpecException {

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(
                password,
                salt,
                ITERATION_COUNT,
                KEY_LENGTH_BIT
        );
        return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
    }

    /**
     * 生成随机盐值
     */
    private static byte[] generateSalt() {
        byte[] salt = new byte[SALT_LENGTH_BYTE];
        new SecureRandom().nextBytes(salt);
        return salt;
    }

    public static void main(String[] args) {
        try {
            String original = "MySecretPassword123";

            // 加密测试（多次加密结果不同）
            System.out.println("Encrypted 1: " + encrypt(original));
            System.out.println("Encrypted 2: " + encrypt(original));

            // 解密验证
            String encrypted = encrypt(original);
            System.out.println("Decrypted: " + decrypt(encrypted));
            System.out.println("验证结果: " + original.equals(decrypt(encrypted)));
        } catch (CryptoException e) {
            e.printStackTrace();
        }
    }
}